package com.casework

import org.joda.time.format.DateTimeFormat
import org.joda.time.format.DateTimeFormatter
import org.apache.commons.lang.WordUtils

class ParseXmlService {

    Map idToLegalCase = [:]
    Map idToNace = [:]
    Map idToFirm = [:]

    void parseEverything(String xml) {
        xml = xml.replaceAll("""Activities of households as employers; undifferentiated goods - and services - producing activities of households for own use""", 'Activities of households as employers')

        parseMeasure(xml)
        parseOffer(xml)
        parseNace(xml)
        parseFirm(xml)
        addFirmsToLegalCase(xml)
        addNaceToLegalCase(xml)
    }

    void parseFiles(String xml){
        def files = new XmlParser().parseText(xml)
        files = files.tblFiles
        files.each{ file ->
            def ecNumber = file.ECNumber.text()
            def name = file.strPath.text()
            name = name.replace(' - ', '-')
            name = name.replace(' ', '-')
            def legalCase = LegalCase.findByEcNumber(ecNumber)
            def attachedFile = new AttachedFile(path:"$ecNumber/$name", contentType: 'pdf', internalFileOnly: false)

            if(!legalCase){
                println  "nothing found for $ecNumber"
            } else{
                legalCase.addToFiles(attachedFile).save(flush:true)
            }
        }
    }



    void addFirmsToLegalCase(String xml) {
        def records = new XmlParser().parseText(xml)
        def joinTable = records.tblCases*.tblFIRMS_AND_CASES.flatten()
        joinTable.every { join ->
            def caseID = join.lngCasesID.text()
            def legalCase = idToLegalCase[caseID]
            def firmID = join.lngFirmsID.text()
            def firm = idToFirm[firmID]
            LegalCaseFirm.create(legalCase, firm, true)
        }
    }

    void addNaceToLegalCase(String xml) {
        def records = new XmlParser().parseText(xml)
        def joinTable = records.tblNACE*.tblNACE_AND_CASES.flatten()
        joinTable.every { join ->
            def caseID = join.lngCasesID.text()
            def legalCase = idToLegalCase[caseID]
            def naceID = join.lngNACEID.text()
            def nace = idToNace[naceID]
            LegalCaseNaceFullDescription.create(legalCase, nace, true)
        }
    }

    DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd")

    void parseMeasure(String xml) {
        Map map = parseLegalCase(xml)
        Map classification = parseClassifications(xml)

        xml = xml.replaceAll('mixed', 'Mixed')
        def records = new XmlParser().parseText(xml)
        def measures = records.tblCases*.tblMeasures.flatten()

        measures.each { m ->
            Measure measure = new Measure()
            measure.fullMeasureDescription = m.memMeasureDescriptionFull.text()
            measure.leadMeasure = m.boolLeadMeasure.text().toBoolean()
            measure.competitionConcern = WordUtils.capitalizeFully(m.strCompetitionConcern.text())
            measure.originOfDivestment = m.strOriginOfDivestment.text() ?: null
            measure.alternativeRemedy = m.strAlternativeRemedy.text() ?: null
            measure.scopeOfDivestment = m.strScopeOfDivestment.text() ? WordUtils.capitalizeFully(m.strScopeOfDivestment.text()) : null
            measure.tangibleFixedAsset = m.strTangibleFixedAssets.text() ?  m.strTangibleFixedAssets.text().replaceAll(' ', '_') : null
            measure.intangibleFixedAsset = m.strIntangibleFixedAssets.text() ? m.strIntangibleFixedAssets.text().replaceAll(' ', '_') : null
            measure.currentAsset = m.strCurrentAssets.text() ? m.strCurrentAssets.text().replaceAll(' ', '_') : null
            measure.personnel = m.strPersonnel.text() ? m.strPersonnel.text().replaceAll(' ', '_') : null
            measure.transitionalService = m.strTransitionalServices.text() ? m.strTransitionalServices.text().replaceAll(' ', '_') : null
            measure.term = m.strTerm.text();
            measure.purchaserCriteria = m.strPurchaserCriteria.text() ? m.strPurchaserCriteria.text().replaceAll(' ', '_') as PurchaserCriteria : null
            measure.clusterSale = m.strClusterSale.text() ? m.strClusterSale.text() as YesNoNA : null

            measure.measureClassification = classification[m.lngMeasureClassifactionID.text()]

            LegalCase legalCase = map[m.lngCasesID.text()]
            legalCase.addToMeasures(measure)
            legalCase.save()
            measure.save(flush: true, failOnError: true)
        }
    }

    Map parseLegalCase(String xml) {
        if (idToLegalCase.size() == 0) {
            Map map = [:]

            def dealTypes = parseDealType(xml)
            def records = new XmlParser().parseText(xml)
            def legalCases = records.tblCases

            legalCases.each { l ->
                LegalCase legalCase = new LegalCase()
                legalCase.ecNumber = l.strECnumber.text().toLong()
                legalCase.notificationDate = fmt.parseDateTime(l.dateNotification.text().replaceAll(/T.*/, '')).toLocalDate()
                legalCase.decisionDate = fmt.parseDateTime(l.dateDecision.text().replaceAll(/T.*/, '')).toLocalDate()
                legalCase.dateOfStatementOfObjections = l.dateStatementOfObjections.text() ? fmt.parseDateTime(l.dateStatementOfObjections.text().replaceAll(/T.*/, '')).toLocalDate() : null
                legalCase.phase = l.intPhase.text().toInteger()
                legalCase.ph1Offer = l.strPh1Offer.text() ? l.strPh1Offer.text().replaceAll(' ', '_') : null
                legalCase.relativeToSO = l.strRelativeToSO.text() ?: null
                legalCase.typeA = l.strTypeA.text() ?: null
                legalCase.typeB = l.strTypeB.text() ? l.strTypeB.text().replaceAll(' ', '_') : null
                legalCase.dealType = dealTypes[l.lngDealTypeID.text()]

                def id = l.lngCasesID.text()
                map."$id" = legalCase.save(failOnError: true)  //missing deal type
            }
            idToLegalCase = map
        }
        return idToLegalCase
    }

    Map parseDealType(String xml) {
        Map map = [:]
        def records = new XmlParser().parseText(xml)
        def dealTypes = records.tblDealType

        dealTypes.each { d ->
            DealType dealType = new DealType()
            dealType.dealType = d.strDealType.text()
            def id = d.lngDealTypeID.text()
            map."$id" = dealType.save(failOnError: true)
        }
        return map
    }

    Map parseFirm(String xml) {
        if (idToFirm.size() == 0) {
            Map map = [:]
            def records = new XmlParser().parseText(xml)
            def firms = records.tblFirms
            firms.each { f ->
                Firm firm = new Firm()
                firm.name = f.strFirms.text()
                map."${f.lngFirmsID.text()}" = firm.save(failOnError: true)
            }
            idToFirm = map
        }
        return idToFirm
    }

    Map parseNaceCategory(String xml) {
        Map map = [:]
        def records = new XmlParser().parseText(xml)
        def naces = records.tblNACECategory

        naces.each { n ->
            NaceCategory category = new NaceCategory()
            category.shortDescription = n.strNACEShortDescription.text().trim()

            String id = n.lngNACEShortDescriptionID.text()
            map."$id" = category.save(failOnError: true)
        }
        return map
    }

    Map parseNace(String xml) {
        if (idToNace.size() == 0) {
            Map map = [:]

            def categories = parseNaceCategory(xml)

            def records = new XmlParser().parseText(xml)
            def naces = records.tblNACE

            naces.each { n ->
                Nace nace = new Nace()
                nace.description = n.strNACEFullDescription.text().trim()
                nace.code = n.strNACECode.text().trim()
                nace.naceCategory = categories[n.lngNACEShortDescriptionID.text()]

                map."${n.lngNACEID.text()}" = nace.save(failOnError: true)
            }
            idToNace = map
        }
        return idToNace
    }

    void parseOffer(String xml) {
        Map map = parseLegalCase(xml)
        def records = new XmlParser().parseText(xml)
        def offers = records.tblCases*.tblOffers
        offers.each {
            it.each { o ->
                if (o) {
                    Offer offer = new Offer()
                    offer.offerDate = fmt.parseDateTime(o.dateOffers.text().replaceAll(/T.*/, '')).toLocalDate()
                    LegalCase legalCase = map[o.lngCasesID.text()]
                    legalCase.addToOffers(offer)
                    legalCase.save()
                    offer.save()
                }
            }
        }
    }

    Map parseClassifications(String xml) {
        def term = new Property(property: 'term').save(failOnError: true, fluah: true)
        def purchaserCriteria = new Property(property: 'purchaserCriteria').save(failOnError: true, fluah: true)
        def clusterSale = new Property(property: 'clusterSale').save(failOnError: true, fluah: true)
        def alternativeRemedy = new Property(property: 'alternativeRemedy').save(failOnError: true, fluah: true)
        def scopeOfDivestment = new Property(property: 'scopeOfDivestment').save(failOnError: true, fluah: true)
        def tangibleFixedAsset = new Property(property: 'tangibleFixedAsset').save(failOnError: true, fluah: true)
        def inteangibleFixedAsset = new Property(property: 'intangibleFixedAsset').save(failOnError: true, fluah: true)
        def currentAsset = new Property(property: 'currentAsset').save(failOnError: true, fluah: true)
        def personnel = new Property(property: 'personnel').save(failOnError: true, fluah: true)
        def transitionalService = new Property(property: 'transitionalService').save(failOnError: true, fluah: true)
        def additionalRequirements = new Property(property: 'additionalRequirements').save(failOnError: true, fluah: true)
        def comments = new Property(property: 'comments').save(failOnError: true, fluah: true)


        Map map = [:]
        def records = new XmlParser().parseText(xml)
        def classes = records.tblMeasureClassification
        classes.each { c ->
            MeasureClassification classification = new MeasureClassification()
            classification.measureClassification1 = c.strMeasureClassification1.text()
            classification.measureClassification2 = c.strMeasureClassification2.text()
            classification.measureClassification3 = c.strMeasureClassification3.text()
            classification.save(failOnError: true)
            map."${c.lngMeasureClassifactionID.text()}" = classification

            def id = c.lngMeasureClassifactionID.text()
            switch (id) {
                case "1":
                    ClassificationProperty.create(purchaserCriteria, classification, true)
                    ClassificationProperty.create(clusterSale, classification, true)
                    ClassificationProperty.create(alternativeRemedy, classification, true)
                    ClassificationProperty.create(scopeOfDivestment, classification, true)
                    ClassificationProperty.create(additionalRequirements, classification, true)
                    ClassificationProperty.create(comments, classification, true)
                    break
                case "2":
                    ClassificationProperty.create(purchaserCriteria, classification, true)
                    ClassificationProperty.create(clusterSale, classification, true)
                    ClassificationProperty.create(alternativeRemedy, classification, true)
                    ClassificationProperty.create(scopeOfDivestment, classification, true)
                    ClassificationProperty.create(additionalRequirements, classification, true)
                    ClassificationProperty.create(comments, classification, true)
                    ClassificationProperty.create(tangibleFixedAsset, classification, true)
                    ClassificationProperty.create(inteangibleFixedAsset, classification, true)
                    ClassificationProperty.create(currentAsset, classification, true)
                    ClassificationProperty.create(personnel, classification, true)
                    ClassificationProperty.create(transitionalService, classification, true)
                    break
                case "3":
                    ClassificationProperty.create(purchaserCriteria, classification, true)
                    ClassificationProperty.create(clusterSale, classification, true)
                    ClassificationProperty.create(alternativeRemedy, classification, true)
                    ClassificationProperty.create(scopeOfDivestment, classification, true)
                    ClassificationProperty.create(additionalRequirements, classification, true)
                    ClassificationProperty.create(comments, classification, true)
                    ClassificationProperty.create(transitionalService, classification, true)
                    break
                case "4":
                    ClassificationProperty.create(purchaserCriteria, classification, true)
                    ClassificationProperty.create(clusterSale, classification, true)
                    ClassificationProperty.create(alternativeRemedy, classification, true)
                    ClassificationProperty.create(scopeOfDivestment, classification, true)
                    ClassificationProperty.create(additionalRequirements, classification, true)
                    ClassificationProperty.create(comments, classification, true)
                    ClassificationProperty.create(tangibleFixedAsset, classification, true)
                    ClassificationProperty.create(inteangibleFixedAsset, classification, true)
                    ClassificationProperty.create(currentAsset, classification, true)
                    ClassificationProperty.create(personnel, classification, true)
                    ClassificationProperty.create(transitionalService, classification, true)
                    break
                case "5":
                    ClassificationProperty.create(purchaserCriteria, classification, true)
                    ClassificationProperty.create(clusterSale, classification, true)
                    ClassificationProperty.create(alternativeRemedy, classification, true)
                    ClassificationProperty.create(scopeOfDivestment, classification, true)
                    ClassificationProperty.create(additionalRequirements, classification, true)
                    ClassificationProperty.create(comments, classification, true)
                    break
                case "6":
                case "7":
                case "13":
                    ClassificationProperty.create(term, classification, true)
                    break
                case "12":
                    ClassificationProperty.create(purchaserCriteria, classification, true)
                    ClassificationProperty.create(clusterSale, classification, true)
                    ClassificationProperty.create(alternativeRemedy, classification, true)
                    ClassificationProperty.create(scopeOfDivestment, classification, true)
                    ClassificationProperty.create(additionalRequirements, classification, true)
                    ClassificationProperty.create(comments, classification, true)
                    break
            }

        }

        if(MeasureClassification.countByMeasureClassification2AndMeasureClassification3("Commitment to grant access", "Termination of exclusive vertical agreements") == 0){
            MeasureClassification classification = new MeasureClassification(
                    measureClassification1: 'Behavioural',
                    measureClassification2: 'Commitment to grant access',
                    measureClassification3: 'Termination of exclusive vertical agreements')
            classification.save(flush:true)
            ClassificationProperty.create(term, classification, true)
        }
        return map
    }

    void addPropertiesToClassification(xml) {
        def term = new Property(property: 'term').save(failOnError: true, fluah: true)
        def purchaserCriteria = new Property(property: 'purchaserCriteria').save(failOnError: true, fluah: true)
        def clusterSale = new Property(property: 'clusterSale').save(failOnError: true, fluah: true)
        def alternativeRemedy = new Property(property: 'alternativeRemedy').save(failOnError: true, fluah: true)
        def scopeOfDivestment = new Property(property: 'scopeOfDivestment').save(failOnError: true, fluah: true)
        def tangibleFixedAsset = new Property(property: 'tangibleFixedAsset').save(failOnError: true, fluah: true)
        def inteangibleFixedAsset = new Property(property: 'intangibleFixedAsset').save(failOnError: true, fluah: true)
        def currentAsset = new Property(property: 'currentAsset').save(failOnError: true, fluah: true)
        def personnel = new Property(property: 'personnel').save(failOnError: true, fluah: true)
        def transitionalService = new Property(property: 'transitionalService').save(failOnError: true, fluah: true)

        //1
        def m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3('Other Structural Commitments', 'Commitments to exit from JV'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(purchaserCriteria, classification, true)
        ClassificationProperty.create(clusterSale, classification, true)
        ClassificationProperty.create(alternativeRemedy, classification, true)
        ClassificationProperty.create(scopeOfDivestment, classification, true)

        //2
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Transfer of a market position',
                'Divestiture of a business unit carved out from a company structure'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(purchaserCriteria, classification, true)
        ClassificationProperty.create(clusterSale, classification, true)
        ClassificationProperty.create(alternativeRemedy, classification, true)
        ClassificationProperty.create(scopeOfDivestment, classification, true)
        ClassificationProperty.create(tangibleFixedAsset, classification, true)
        ClassificationProperty.create(inteangibleFixedAsset, classification, true)
        ClassificationProperty.create(currentAsset, classification, true)
        ClassificationProperty.create(personnel, classification, true)
        ClassificationProperty.create(transitionalService, classification, true)

        //3
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Transfer of a market position',
                'Divestiture of a controlling stake in a viable standalone business'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(purchaserCriteria, classification, true)
        ClassificationProperty.create(clusterSale, classification, true)
        ClassificationProperty.create(alternativeRemedy, classification, true)
        ClassificationProperty.create(scopeOfDivestment, classification, true)
        ClassificationProperty.create(transitionalService, classification, true)

        //4
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Transfer of a market position',
                'Divestiture of assets package'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(purchaserCriteria, classification, true)
        ClassificationProperty.create(clusterSale, classification, true)
        ClassificationProperty.create(alternativeRemedy, classification, true)
        ClassificationProperty.create(scopeOfDivestment, classification, true)
        ClassificationProperty.create(tangibleFixedAsset, classification, true)
        ClassificationProperty.create(inteangibleFixedAsset, classification, true)
        ClassificationProperty.create(currentAsset, classification, true)
        ClassificationProperty.create(personnel, classification, true)
        ClassificationProperty.create(transitionalService, classification, true)

        //5
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Transfer of a market position',
                'Divestiture or grant of long-term licence'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(purchaserCriteria, classification, true)
        ClassificationProperty.create(clusterSale, classification, true)
        ClassificationProperty.create(alternativeRemedy, classification, true)
        ClassificationProperty.create(scopeOfDivestment, classification, true)

        //6
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Commitment to grant access',
                'Granting of access to infrastructure'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(term, classification, true)

        //7
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Commitment to grant access',
                'Granting of access to technology'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(term, classification, true)

        //12
        m = MeasureClassification.findByMeasureClassification2AndMeasureClassification3(
                'Other Structural Commitment',
                'Other structural'
        )
        m.save(failOnError: true, fluah: true)
        ClassificationProperty.create(purchaserCriteria, classification, true)
        ClassificationProperty.create(clusterSale, classification, true)
        ClassificationProperty.create(alternativeRemedy, classification, true)
        ClassificationProperty.create(scopeOfDivestment, classification, true)
    }
}